package com.wf.netty.bytebuf;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ByteBuf分配
 *
 * @author wf
 * @since 2022/5/25
 */
public class AllocatorTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(AllocatorTest.class);

    //输出ByteBuf是否为直接内存，以及内存分配器
    public static void printByteBuf(String action, ByteBuf b) {
        LOGGER.info(" ===========" + action + "============");
        //true表示缓冲区为Java堆内存（组合缓冲例外）
        //false表示缓冲区为操作系统管理的内存（组合缓冲例外）
        LOGGER.info("b.hasArray: " + b.hasArray());

        //输出内存分配器
        LOGGER.info("b.ByteBufAllocator: " + b.alloc());
    }

    static class AllocDemoHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            printByteBuf("入站", (ByteBuf) msg);

            ByteBuf buffer = ctx.alloc().buffer();
            buffer.writeInt(100);
            ctx.writeAndFlush(buffer);
        }
    }

    @Test
    public void testByteBufAlloc() {
        ChannelInitializer<EmbeddedChannel> i = new ChannelInitializer<EmbeddedChannel>()
        {
            protected void initChannel(EmbeddedChannel ch)
            {
                ch.pipeline().addLast(new AllocDemoHandler());
            }
        };
        EmbeddedChannel channel = new EmbeddedChannel(i);
        //配置通道的缓冲区分配器，这里设置一个池化的分配器
        channel.config().setAllocator(PooledByteBufAllocator.DEFAULT);
        ByteBuf buf = Unpooled.buffer();
        buf.writeInt(1);
        //向模拟通道写入一个入站包，模拟数据入站
        channel.writeInbound(buf);
        //获取通道的出站包
        ByteBuf outBuf = (ByteBuf) channel.readOutbound();
        printByteBuf("出站的ByteBuf", outBuf);
        //省略不相关代码
    }

    @Test
    public  void testSlice() {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(9, 100);
        printByteBuf("动作：分配ByteBuf(9, 100)", buffer);
        buffer.writeBytes(new byte[]{1, 2, 3, 4});
        printByteBuf("动作：写入4个字节 (1,2,3,4)", buffer);
        ByteBuf slice = buffer.slice();
        printByteBuf("动作：切片 slice", slice);
    }
}
